/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bea.logic;

import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author Septu Jamasoka
 */
public class BananaEngine {

    byte[] block = new byte[8];
    public BananaKey key = new BananaKey();
    ArrayList<byte[]> listplain = new ArrayList<byte[]>();
    ArrayList<byte[]> listcipher = new ArrayList<byte[]>();

    public void f(byte[] bb, int ii) {
        byte[] k = key.genKeyFeistel(ii);
        for (int j = 0; j < 4; j++) {
            bb[j] = (byte) (bb[j] ^ k[j]);
        }
    }

    public byte[] enkrip() {


        for (int g = 0; g < 8; g++) {
            byte[] l = new byte[4];
            byte[] r = new byte[4];
            System.arraycopy(block, 0, l, 0, 4);
            System.arraycopy(block, 4, r, 0, 4);

            for (int i = 0; i < 16; i++) {

                byte[] temp = new byte[r.length];
                System.arraycopy(r, 0, temp, 0, r.length);
                f(r, (i + g));
                for (int j = 0; j < 4; j++) {
                    r[j] = (byte) (r[j] ^ l[j]);
                }

                System.arraycopy(temp, 0, l, 0, temp.length);
                //System.out.println("feistel " + i);
            }
            System.arraycopy(l, 0, block, 0, 4);
            System.arraycopy(r, 0, block, 4, 4);
        }

        return block;
    }

    public byte[] dekrip() {
        for (int g = 1; g < 9; g++) {
            byte[] l = new byte[4];
            byte[] r = new byte[4];
            System.arraycopy(block, 0, l, 0, 4);
            System.arraycopy(block, 4, r, 0, 4);
            for (int i = 23; i > 7; i--) {

                byte[] temp = new byte[l.length];
                System.arraycopy(l, 0, temp, 0, l.length);
                f(l, (i - g));
                for (int j = 0; j < 4; j++) {
                    l[j] = (byte) (l[j] ^ r[j]);
                }
                System.arraycopy(temp, 0, r, 0, temp.length);
                //System.out.println("feistel dekrip k" + i);
            }
            System.arraycopy(l, 0, block, 0, 4);
            System.arraycopy(r, 0, block, 4, 4);
        }
        String hasil = new String(block);
        return block;
    }

    public void setplain(byte[] b) {
        listcipher.clear();
        listplain.clear();
        for (int i = 0; i < b.length / 8; i++) {
            byte[] nb = new byte[8];
            for (int j = 0; j < 8; j++) {
                nb[j] = 0;
            }
            System.arraycopy(b, (i * 8), nb, 0, 8);
            listplain.add(nb);
        }

        if (b.length % 8 != 0) {
            byte[] nb = new byte[8];
            for (int j = 0; j < 8; j++) {
                nb[j] = 0;
            }
            System.arraycopy(b, (b.length / 8) * 8, nb, 0, b.length % 8);
            listplain.add(nb);
        }

    }

    public void setcipher(byte[] b) {
        listcipher.clear();
        listplain.clear();
        for (int i = 0; i < b.length / 8; i++) {
            byte[] nb = new byte[8];
            for (int j = 0; j < 8; j++) {
                nb[j] = 0;
            }
            System.arraycopy(b, (i * 8), nb, 0, 8);
            listcipher.add(nb);
        }

    }

    public byte[] genIV() {

        byte[] IV = new byte[8];
        Random r = new Random();

        for (int i = 0; i < 8; i++) {
            int x = r.nextInt(128);
            IV[i] = (byte) (x);
        }
        return IV;
    }

    public void cfbEncrypt() {
        byte[] IV = genIV();
        byte[] antrian = new byte[8];
        byte[] plain = new byte[8];
        byte[] hasiltemp = new byte[8];
        byte[] hasilcipher = new byte[8];
        int i = 0;
        int prev = 0;
        listcipher.add(IV);
        while (i < listplain.size()) {
            hasiltemp = new byte[8];
            hasilcipher = new byte[8];
            plain = new byte[8];
            antrian = new byte[8];
            System.arraycopy(listplain.get(i), 0, plain, 0, 8);
            if (prev == 0) {
                System.arraycopy(IV, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    if (getBit(hasiltemp, 0) == 1) {
                        setBit(plain, j * 8, 1);
                    }
                    hasilcipher[j] = (byte) (hasiltemp[0] ^ plain[j]);
//                     if (hasilcipher[j] == 13) {
//                         hasilcipher[j] = -92;
//                     } else if (hasilcipher[j] == 10) {
//                         hasilcipher[j] = -90;
//                     }
                    if (hasilcipher[j] < 32) {
                        hasilcipher[j] -= 48;
                    }
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasilcipher[j];


                }
            } else {
                System.arraycopy(listcipher.get(prev), 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    if (getBit(hasiltemp, 0) == 1) {
                        setBit(plain, j * 8, 1);
                    }
                    hasilcipher[j] = (byte) (hasiltemp[0] ^ plain[j]);
//                     if (hasilcipher[j] == 13) {
//                         hasilcipher[j] = -92;
//                     } else if (hasilcipher[j] == 10) {
//                         hasilcipher[j] = -90;
//                     }
                    if (hasilcipher[j] < 32) {
                        hasilcipher[j] -= 48;
                    }
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasilcipher[j];
                }
                System.err.println(antrian);
            }
            listcipher.add(hasilcipher);
            i++;
            prev++;
        }

    }

    public void cfbDecrypt() {
        byte[] IV = listcipher.get(0); //harusnya blok pertama
        byte[] antrian = new byte[8];
        byte[] cipher = new byte[8];
        byte[] hasiltemp = new byte[8];
        byte[] hasilplain = new byte[8];
        int i = 1;
        int prev = -1;
        while (i < listcipher.size()) {
            hasiltemp = new byte[8];
            hasilplain = new byte[8];
            cipher = new byte[8];
            antrian = new byte[8];
            System.arraycopy(listcipher.get(i), 0, cipher, 0, 8);
            if (prev == -1) {
                System.arraycopy(IV, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    byte er = cipher[j];
//                     if (cipher[j] == -92) {
//                         cipher[j] = 13;
//                     } else if (cipher[j] == -90) {
//                         cipher[j] = 10;
//                     }
                    if (cipher[j] < 0) {
                        cipher[j] += 48;
                    }
                    if (getBit(hasiltemp, 0) == 1) {
                        setBit(cipher, j * 8, 1);
                    }
                    hasilplain[j] = (byte) (hasiltemp[0] ^ cipher[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = er;



                }
            } else {
                System.arraycopy(listcipher.get(i - 1), 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    byte er = cipher[j];
//                     if (cipher[j] == -92) {
//                         cipher[j] = 13;
//                     } else if (cipher[j] == -90) {
//                         cipher[j] = 10;
//                     }
                    if (cipher[j] < 0) {
                        cipher[j] += 48;
                    }
                    if (getBit(hasiltemp, 0) == 1) {
                        setBit(cipher, j * 8, 1);
                    }
                    hasilplain[j] = (byte) (hasiltemp[0] ^ cipher[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = er;
                }
            }
            listplain.add(hasilplain);
            i++;
            prev++;
        }

    }

    public byte[] gethasil(boolean t) {
        byte[] hasil;
        if (t == true) {
            hasil = new byte[(listcipher.size()) * 8];
            for (int i = 0; i < listcipher.size(); i++) {
                System.arraycopy(listcipher.get(i), 0, hasil, i * 8, 8);
            }
        } else {
            hasil = new byte[(listplain.size()) * 8];
            for (int i = 0; i < listplain.size(); i++) {
                System.arraycopy(listplain.get(i), 0, hasil, i * 8, 8);
            }
            int c = hasil.length - 1;
            while (hasil[c] == 0) {
                c--;
            }
            byte[] temp = new byte[c + 1];
            System.arraycopy(hasil, 0, temp, 0, c + 1);
            hasil = new byte[c + 1];
            System.arraycopy(temp, 0, hasil, 0, c + 1);
        }

        return hasil;
    }

    private static int getBit(byte[] data, int pos) {
        int posByte = pos / 8;
        int posBit = pos % 8;
        byte valByte = data[posByte];
        int valInt = valByte >> (8 - (posBit + 1)) & 0x0001;
        return valInt;
    }

    private static void setBit(byte[] data, int pos, int val) {
        int posByte = pos / 8;
        int posBit = pos % 8;
        byte oldByte = data[posByte];
        oldByte = (byte) (((0xFF7F >> posBit) & oldByte) & 0x00FF);
        byte newByte = (byte) ((val << (8 - (posBit + 1))) | oldByte);
        data[posByte] = newByte;
    }

    public static int unsignedByteToInt(byte b) {
        return (int) b & 0xFF;
    }
}